﻿package ru.indee.ui.detectForm 
{
	import flash.display.Sprite;
	import flash.geom.Point;
	import ru.indee.geom.line;
	
	/**
	 * ...
	 * @author Raidnew
	 */
	public class processingForm 
	{
		
		public function processingForm() 
		{
			
		}
		
		/**
		 * Суём сюда объект типа objectForDetect с кучей точек от движения мыши и приходит обратно объект
		 * с минимальным кол-вом точек, для удобства анализирования в detectLogic
		 * @param	form
		 * @return
		 */
		public static function removeNoiseForm(form:objectForDetect):objectForDetect {
			
			if (form.getFullLengthForm() < 5) {
				return form;
			}
			
			var formForProccesing:objectForDetect = new objectForDetect(form.getPointsArray());
			
			//trace("BEFORE"+formForProccesing.getPointsArray().length);
			
			formForProccesing = removeZeroAngle(formForProccesing);
			formForProccesing = removeNoiseAngle(formForProccesing);

			var finishKey:Boolean = false;
			
			while (!finishKey) {
				var beforeCountPoint:Number = formForProccesing.getPointsArray().length;
				formForProccesing = removeSmallestAverageAngle(formForProccesing);
				var afterCountPoint:Number = formForProccesing.getPointsArray().length;
				if (beforeCountPoint == afterCountPoint) finishKey = true;
			}
			
			formForProccesing = removePointOnShortDistance(formForProccesing);
			return formForProccesing;
		}
		
		/**
		 * Удаляет углы близкие к 0, какие углы близкие к 0, смотри в настройках
		 * @param	form
		 * @return
		 */
		private static function removeZeroAngle(form:objectForDetect):objectForDetect {
			var arrPoint:Array = form.getPointsArray();
			var arrAngles:Array = form.getAngleArray();
			var retArray:Array = new Array();
			
			retArray.push(arrPoint[0]);
			for (var i:Number = 0; i < arrAngles.length; i++) {
				if (Math.abs(arrAngles[i]) < settingLogic.zeroAngle) {
					
				}else {
					retArray.push(arrPoint[i+1]);
				}
			}
			retArray.push(arrPoint[arrPoint.length - 1]);
			form.setPointArray(retArray);
			return form;
		}		
		
		/**
		 * удаляем шумовые углы, т.е. если соотношения положительных и отрицательных меньше как-то величины то меньшинство подвергаем жесткому геноциду
		 * @param	form
		 * @return
		 */
		private static function removeNoiseAngle(form:objectForDetect):objectForDetect {
			var arrPoint:Array = form.getPointsArray();
			var arrAngles:Array = form.getAngleArray();
			var retArray:Array = new Array();
			
			var countAnglesNeg:Number = 0;
			var countAnglesPos:Number = 0;
			
			for (var i:Number = 0; i < arrAngles.length; i++) {
				if (arrAngles[i] > 0) countAnglesPos++;
				if (arrAngles[i] < 0) countAnglesNeg++;
			}

			if (countAnglesPos < (countAnglesNeg * 0.1)) {
				retArray.push(arrPoint[0]);
				for (i = 0; i < arrAngles.length; i++) {
					if (arrAngles[i] < 0) {
						retArray.push(arrPoint[i+1]);
					}
				}
				retArray.push(arrPoint[arrPoint.length - 1]);
			}else if (countAnglesNeg < (countAnglesPos * 0.1)) {
				retArray.push(arrPoint[0]);
				for (i = 0; i < arrAngles.length; i++) {
					if (arrAngles[i] > 0) {
						retArray.push(arrPoint[i+1]);
					}
				}
				retArray.push(arrPoint[arrPoint.length - 1]);
			}else {
				retArray = arrPoint;
			}
			
			form.setPointArray(retArray);
			return form;
		}		
		
		/**
		 * при помощи бубна и плясок вычисляем средний угол умножем его на коэффициент и нагло убиваем все углы меньше полученного
		 * @param	form
		 * @return
		 */
		private static function removeSmallestAverageAngle(form:objectForDetect):objectForDetect {
			//Находим срелдний угол а неподходящие кторые меньше удаляем нафиг
			
			var PointArray:Array = form.getPointsArray();
			var angleArray:Array = form.getAngleArray(false);// detectLogic.getArrayAngle(tempArray);
			
			var averageAngle:Number = form.getAverageAngle();
			
			var retArray:Array = new Array();
			
			retArray.push(PointArray[0]);
			
			for(var i:Number = 0; i < angleArray.length; i++) {
				if (Math.abs(angleArray[i]) < (averageAngle * settingLogic.angleProportion)) {
					
				}else {
					retArray.push(PointArray[i+1]);
				}
			}
			
			retArray.push(PointArray[PointArray.length - 1]);
			
			return new objectForDetect(retArray);
		}
		
		/**
		 * находим среднее растояние между точками, умножаем опять-же на коэффициент (шоб не удалялось всё что меньше
		 * ибо предполагаем что меньше среднего могут быть и выжные точки) в общем почитали поделили и удалили (но хитро)
		 * 
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!
		 * Есть идея наворота алгоритма
		 * в процессе раздумий
		 * !!!!!!!!!!!!!!!!!!!!!!!!!!
		 * 
		 * @param	form
		 * @return
		 */
		private static function removePointOnShortDistance(form:objectForDetect):objectForDetect {
			var arrPoints:Array = form.getPointsArray();
			
			var newArray:Array = new Array();
			
			var collectorSnapPoint:Array = new Array();

			var averageDistance:Number = (form.getFullLengthForm() / (form.getPointsArray().length - 1)) * settingLogic.coeffDistanceSmallestAverage;
			
			var keyFindSmallDistance:Boolean = false;
			
			//var testSprite:Sprite = new Sprite();
			
			var distanceBeforePoint:Number = 0;
			
			/*
			var testStart:Number = 0;
			var testStop:Number = 0;
			*/
			
			for (var i:Number = 0; i < arrPoints.length; i++) {
				
				//output.out("POINT: "+i);
				
				if((i<(arrPoints.length - 1))){
					distanceBeforePoint = Point.distance(arrPoints[i], arrPoints[i + 1]);
				}else {
					distanceBeforePoint = 0
				}
				
				if ((distanceBeforePoint < averageDistance)&&(i<(arrPoints.length - 1))) {
					if (!keyFindSmallDistance) {
						//testStart = i;
						
						collectorSnapPoint = new Array();
						collectorSnapPoint.push(arrPoints[i]);
						
						keyFindSmallDistance = true;
					}
					
					collectorSnapPoint.push(arrPoints[i + 1]);
				
					/*
					testStop = (i + 1);
					
					testSprite.graphics.lineStyle(4, 0x333333);
					testSprite.graphics.moveTo(arrPoints[i+1].x,arrPoints[i+1].y);
					testSprite.graphics.lineTo(arrPoints[i].x, arrPoints[i].y);
					*/
				}else {
					
					if (keyFindSmallDistance) {
						keyFindSmallDistance = false;
						
						var newx:Number = 0;
						var newy:Number = 0;
						
						for (var j:Number = 0; j < collectorSnapPoint.length; j++) {
							newx += collectorSnapPoint[j].x;
							newy += collectorSnapPoint[j].y;
						}
						
						newx = newx / collectorSnapPoint.length;
						newy = newy / collectorSnapPoint.length;
						
						newArray.push(new Point(newx, newy));
						
						//output.out("ADD COLLAPSE: "+testStart+" : "+testStop);
						/*
						testSprite.graphics.lineStyle(2, 0xFF0000);
						testSprite.graphics.drawCircle(newx, newy, 10);
						*/
					}else {
						
						//output.out("ADD NORMAL: "+i);
						
						newArray.push(arrPoints[i]);
					}
				}
			}
			
			//output.addChild(testSprite);
			
			return new objectForDetect(newArray);
		}
		
		/**
		 * ну тут всё тупо до безобразия
		 * первый нах
		 * ВтАрОй НаХ
		 * Замыкаю пьедестал
		 * 
		 * Гыы.. посрали в каментах
		 * 
		 * @param	form
		 * @return
		 */
		public static function detectCloseForm(form:objectForDetect):Boolean {
			
			var arrayDetect:Array = form.getPointsArray();
			
			var maxSize:Number = form.getFullLengthForm();// getLengthForm(arrayDetect);
			
			if (Point.distance(arrayDetect[0], arrayDetect[arrayDetect.length - 1]) < (settingLogic.distanceForDetectCloseFormInPercent * maxSize)) {
				return true;
			}else{
				return false;
			}
		}		
	}
	
}